/**
 * 旋转矩阵 - L5
 *
 * 主要处理物体-惯性坐标系间的旋转
 * 所以该矩阵表示的只是方位
 * @author lonphy
 * @version 0.1
 */
(function(L5) {
	"use strict";

	function initConstructor() {
		/**
		 * 旋转矩阵构造
		 * @constructor
		 */
		L5.RotateMatrix = function() {
			// 3x3矩阵
			this.content = new Float32Array(9);
		};
	}
	function initMethods() {
		var $fn = L5.RotateMatrix.prototype;
		/**
		 * 置为单位矩阵
		 * @returns {L5.RotateMatrix}
		 */
		$fn.identity = function() {
			this.content[0] = this.content[4] = this.content[8] = 1;
			this.content[1] = this.content[3] = this.content[6] = 0;
			this.content[2] = this.content[5] = this.content[7] = 0;
			return this;
		};
		/**
		 * 克隆
		 * @returns {L5.RotateMatrix}
		 */
		$fn.clone = function(){
			var ret = new L5.RotateMatrix();
			ret.content = new Float32Array(this.content);
			return ret;
		};
		/**
		 * 根据欧拉角构造矩阵
		 * @param euler {L5.Euler} 代表方位的欧拉角
		 * @return {L5.RotateMatrix}
		 */
		$fn.setup = function(euler) {
			var sp = Math.sin(euler.pitch),
				sb = Math.sin(euler.bank),
				sh = Math.sin(euler.heading),
				cp = Math.cos(euler.pitch),
				cb = Math.cos(euler.bank),
				ch = Math.cos(euler.heading);
			this.content[0] = ch*cb + sh*sp*sb;
			this.content[1] = -ch*sb + sh*sp*cb;
			this.content[2] = sh*cp;
			this.content[3] = sb*cp;
			this.content[4] = cb*cp;
			this.content[5] = -sp;
			this.content[6] = -sh*cb +ch*sp*sb;
			this.content[7] = sb*sh + ch*sp*cb;
			this.content[8] = ch*cp;
			return this;
		};
		/**
		 * 根据四元数构造矩阵[物体-惯性]
		 * 4元素代表指定方向的变换
		 * @param qua {L5.Quaternion}
		 * @returns {L5.RotateMatrix}
		 */
		$fn.fromObjectToInertiaQuaternion = function(qua) {
			this.content[0] = 1 - 2*(qua.y*qua.y +qua.z*qua.z);
			this.content[1] = 2 * (qua.x*qua.y - qua.w*qua.z);
			this.content[2] = 2 * (qua.x*qua.z + qua.w*qua.y);
			this.content[3] = 2 * (qua.x*qua.y + qua.w*qua.z);
			this.content[4] = 1 - 2*(qua.x*qua.x +qua.z*qua.z);
			this.content[5] = 2 * (qua.y*qua.z - qua.w*qua.x);
			this.content[6] = 2 * (qua.x*qua.z - qua.w*qua.y);
			this.content[7] = 2 * (qua.y*qua.z + qua.w*qua.x);
			this.content[8] = 1 - 2*(qua.x*qua.x +qua.y*qua.y);
			return this;
		};
		/**
		 * 根据四元数构造矩阵[惯性-物体]
		 * 4元素代表指定方向的变换
		 * @param qua {L5.Quaternion}
		 * @returns {L5.RotateMatrix}
		 */
		$fn.fromInertiaToObjectQuaternion = function(qua) {
			this.content[0] = 1 - 2*(qua.y*qua.y +qua.z*qua.z);
			this.content[1] = 2 * (qua.x*qua.y + qua.w*qua.z);
			this.content[2] = 2 * (qua.x*qua.z - qua.w*qua.y);
			this.content[3] = 2 * (qua.x*qua.y - qua.w*qua.z);
			this.content[4] = 1 - 2*(qua.x*qua.x +qua.z*qua.z);
			this.content[5] = 2 * (qua.y*qua.z + qua.w*qua.x);
			this.content[6] = 2 * (qua.x*qua.z - qua.w*qua.y);
			this.content[7] = 2 * (qua.y*qua.z - qua.w*qua.x);
			this.content[8] = 1 - 2*(qua.x*qua.x +qua.y*qua.y);
			return this;
		};
		/**
		 * 执行转换[物体-惯性]
		 * @param vec3 {L5.FVec3}
		 * @returns {L5.FVec3}
		 */
		$fn.objectToInertia = function(vec3) {
			return new L5.FVec3(
				this.content[0]*vec3.x + this.content[1]*vec3.y + this.content[2]*vec3.z,
				this.content[3]*vec3.x + this.content[4]*vec3.y + this.content[5]*vec3.z,
				this.content[6]*vec3.x + this.content[7]*vec3.y + this.content[8]*vec3.z
			);
		};
		/**
		 * 执行转换[惯性-物体]
		 * @param vec3 {L5.FVec3}
		 * @returns {L5.FVec3}
		 */
		$fn.inertiaToObject = function(vec3) {
			return new L5.FVec3(
				this.content[0]*vec3.x + this.content[3]*vec3.y + this.content[6]*vec3.z,
				this.content[1]*vec3.x + this.content[4]*vec3.y + this.content[7]*vec3.z,
				this.content[2]*vec3.x + this.content[5]*vec3.y + this.content[8]*vec3.z
			);
		};
		/**
		 * 打印
		 */
		$fn.print = function() {
			console.log(this.toString());
		};
		/**
		 * toString复写
		 * @returns {string}
		 */
		$fn.toString = function() {
			var i, j,
				out = 'RotateMatrix:\n';
			for(i=0;i<3;++i) {
				out += '|';
				for(j=0;j<3;++j) {
					out += ' ' + this.content[i*3+j].toFixed(8, 10) + ' ';
				}
				out += '|\n';
			}
			return out;
		};
		/**
		 * 转为数组
		 * @returns {Float32Array}
		 */
		$fn.toArray = function() {
			return this.content;
		};
	}
	function setupAlias() {
		var $fn = L5.RotateMatrix.prototype;
		// 设置m11 - m33访问器
		L5.define(true, $fn, 'm11', {
			get: function () { return this.content[0]; },
			set: function (val) { this.content[0] = val; }
		});
		L5.define(true, $fn, 'm12', {
			get: function () { return this.content[1]; },
			set: function (val) { this.content[1] = val; }
		});
		L5.define(true, $fn, 'm13', {
			get: function () { return this.content[2]; },
			set: function (val) { this.content[2] = val; }
		});
		L5.define(true, $fn, 'm21', {
			get: function () { return this.content[3]; },
			set: function (val) { this.content[3] = val; }
		});
		L5.define(true, $fn, 'm22', {
			get: function () { return this.content[4]; },
			set: function (val) { this.content[4] = val; }
		});
		L5.define(true, $fn, 'm23', {
			get: function () { return this.content[5]; },
			set: function (val) { this.content[5] = val; }
		});
		L5.define(true, $fn, 'm31', {
			get: function () { return this.content[6]; },
			set: function (val) { this.content[6] = val; }
		});
		L5.define(true, $fn, 'm32', {
			get: function () { return this.content[7]; },
			set: function (val) { this.content[7] = val; }
		});
		L5.define(true, $fn, 'm33', {
			get: function () { return this.content[8]; },
			set: function (val) { this.content[8] = val; }
		});
	}
	initConstructor();
	initMethods();
	setupAlias();
})(window.L5);
